<?php
###
#  Baing PHP 框架 1.0.0
#  http://baing.co/
#
#  Copyright: 白晓阳
#  License: CC BY-NC-SA 4.0
#  https://creativecommons.org/licenses/by-nc-sa/4.0/deed.zh
###

namespace bai\resource\document;

use bai\feature\RequestException;
use bai\feature\Agent;
use bai\Response;


class DataTable extends \bai\resource\document\Php
{
    protected static array $getters = ['name', 'id'];

    protected array $runtime = [
        'configurable' => true
    ];

    public function run()
    {
        $data = parent::run();
        return $this->runtime = array_replace_recursive($this->runtime, $data);
    }

    public function findFieldName(string $field): ?string
    {
        $columns = $this->find('columns');
        return $columns[$field]['name'] ?? $field;
    }

    public function findSoftDelete(): bool
    {
        $data = $this->find('data') ?? [];
        foreach ($data as $def) {
            if (isset($def[self::DELETE])) {
                return true;
            }
        }
        return false;
    }

    public function filterFields(string|array|null $include, ?array $exclude = null): array
    {
        $fields = $this->find('fields') ?? [];
        $include = $include ?? $fields['include'] ?? '*';
        $exclude = $exclude ?? $fields['exclude'] ?? [];
        if ($include === '*') {
            $include = array_keys($this->find('columns'));
        }
        $include = array_diff((array)$include, $exclude);
        return $this->filter($include);
    }

    public function filterQuery(array $input, string $method): array
    {
        $query = $this->prepare($this->find('query') ?? [], $method);
        $replace = [];
        foreach ($query as $name => $value) {
            if ($value !== null) {
                $input[$name] = $value;
                continue;
            }
            if (array_key_exists($name, $input)) {
                $replace[$name] = true;
            }
        }
        $input = array_diff_key($input, $replace);
        $input = array_intersect_key($input, $this->find('columns'));
        return $input;
    }

    public function filterData(array $input, string $method): array
    {
        $data = $this->prepare($this->find('data') ?? [], $method);
        $replace = [];
        foreach ($data as $name => $value) {
            if ($value !== null) {
                $input[$name] = $value;
                continue;
            }
            if (array_key_exists($name, $input)) {
                $replace[$name] = true;
            }
        }
        $input = array_diff_key($input, $replace);

        $columns = $this->find('columns');
        $input = array_intersect_key($input, $columns);
        foreach ($input as $name => &$value) {
            $encoder = $columns[$name]['encode'] ?? null;
            if (is_callable($encoder)) {
                $value = $encoder($value);
            }
        }
        return $input;
    }

    public function filterQuality(array $input): array
    {
        $quality = array_replace_recursive($this->find('quality') ?? [], $input);
        return $quality;
    }

    public function filterLinks(array $input): array
    {
        $links = $this->find('links') ?? [];
        $items = [];
        foreach ($input as $key => $value) {
            if (is_string($value) && isset($links[$value])) {
                $items[$value] = $links[$value];
                continue;
            }
            if (is_array($value) && isset($links[$key])) {
                $items[$key] = array_replace($value, $links[$key]);
            }
        }
        return $items;
    }

    protected function filter(array $fields): array
    {
        $columns = $this->find('columns');
        $alias = $this->find('alias') ?? [];

        $items = [];
        foreach ($fields as $field) {
            if (isset($columns[$field])) {
                $items[$field] = $columns[$field];
                continue;
            }
            if (isset($alias[$field])) {
                $items[$field] = $alias[$field];
                continue;
            }
        }
        return $items;
    }

    protected function prepare(array $data, string $method): array
    {
        $params = [];
        foreach ($data as $name => $def) {
            if (!array_key_exists($method, $def)) continue;
            $value = $def[$method];
            if (is_string($value) && $value[0] === '$') {
                $value = Agent::pick($value);
                if ($value === null) {
                    throw new RequestException(code: Response::STATUS_UNAUTHORIZED);
                }
            }
            $params[$name] = $value;
        }
        return $params;
    }
}
